home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 July: Mac OS SDK / Dev.CD Jul 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Typography Samples / Basic Layout Sample ƒ / Basic Layout.c next >
Encoding:
C/C++ Source or Header  |  1996-06-18  |  18.6 KB  |  552 lines  |  [TEXT/KAHL]

  1. /**\
  2. |**| =====================================================================
  3. |**|
  4. |**|    Basic Layout Sample.c
  5. |**|
  6. |**|    This file contains the calls that this sample needs to make
  7. |**|    the QuickDraw GX shell work correctly.
  8. |**|
  9. |**|    QuickDraw GX Libraries Used:
  10. |**|    "ColorLibrary.c", "FontLibrary.c", "GraphicsDebugLibrary.c",
  11. |**|    "LayoutLibrary.c", "ShapeLibrary.c", and "TransformLibrary.c".
  12. |**|
  13. |**|    Written by Eric Mader and Robert Dierkes
  14. |**|
  15. |**|
  16. |**|    6/96 bob        Updated #includes to support changed GX Library names.
  17. |**|                    Updated the copyright date.
  18. |**|    9/93 MD            change QDLocalToFixedGlobal to GXConvertQDPoint,
  19. |**|                    including removing validation just for B2
  20. |**|
  21. |**|    ©1990 - 1996  Apple Computer, Inc.
  22. |**|    All rights reserved.
  23. |**|
  24. |**| =====================================================================
  25. \**/
  26.  
  27. #include "QDGX shell.h"
  28. #include <GXLayout.h>
  29. #include "LayoutLibrary.h"
  30. #include "FontMenuLibrary.h"
  31.  
  32.  
  33. /**\
  34. |**| ---------------------------------------------------------------------
  35. |**| PROTOTYPES
  36. |**| ---------------------------------------------------------------------
  37. \**/
  38.  
  39. // funtions required by shell
  40.  
  41. void    DoSetup            (void);
  42. void    DoDraw            (WindowPtr wind, Boolean updating);
  43. OSErr    DoCreateNew        (void);
  44. void    DoDispose        (WindowPtr wind);
  45. void    DoIdle            (WindowPtr wind);
  46. void    DoTeardown        (void);
  47. void    DoClick            (WindowPtr wind, Point p);
  48.  
  49. // private functions
  50.  
  51. OSErr    DoWindowInit        (WindowPtr wind);
  52. void    CreateSampleImage    (WindowPtr wind);
  53.  
  54.  
  55. /**\
  56. |**| ---------------------------------------------------------------------
  57. |**| ENUMS
  58. |**| ---------------------------------------------------------------------
  59. \**/
  60. enum { rWindResource = 128, rStartOfHeirMenus=140 };
  61.  
  62.  
  63. /**\
  64. |**| ---------------------------------------------------------------------
  65. |**| GLOBALS
  66. |**| ---------------------------------------------------------------------
  67. \**/
  68. // If gDebugging = TRUE, graphics library errors and notices will be posted.  This
  69. // functionality will only work with the "debugging" version of QuickDraw GX.
  70. // If the debugging version is not installed, nothing bad will happen, but these
  71. // functions will not work. 
  72.  
  73. Boolean        gDebugging = true;
  74.  
  75. // Set  "gGiveMeValidation" to TRUE if you want receive run-time validation.
  76.  
  77. Boolean        gGiveMeValidation = true;
  78.  
  79.  
  80. // gGraphicsHeapSize sets the size of the graphics heap created by calling the
  81. // GXNewGraphicsClient routine in main () within QuickDraw GX shell.c.  You can determine
  82. // the amount of graphics heap required by using GraphicsBug.  I'm giving it 600K,
  83. // since we need abunch if we have several windows open.
  84.  
  85. long        gGraphicsHeapSize = 600;
  86.  
  87. // gOurPrintingOverrideUPP is a universal proc pointer for our printing event
  88. // override.  This is so that our override can be native PowerPC code if necessary.
  89.  
  90. GXPrintingEventUPP    gOurPrintingOverrideUPP;
  91.  
  92.  
  93.  
  94. /**\
  95. |**| ---------------------------------------------------------------------
  96. |**| DoSetup()
  97. |**| Here's where we initialize any global variables our application needs.
  98. |**| We have only one at this time -- the universal proc pointer for
  99. |**| our printing override.
  100. |**| ---------------------------------------------------------------------
  101. \**/
  102. void DoSetup (void)
  103. {    // Initialize our printing event override UPP
  104.     gOurPrintingOverrideUPP = NewGXPrintingEventProc(MyPrintingEventOverride);
  105.  
  106.     EnableItem(GetMHandle(mEdit), 0);
  107.     DisableItem(GetMHandle(mEdit), iUndo);
  108.     EnableItem(GetMHandle(mEdit), iCut);
  109.     EnableItem(GetMHandle(mEdit), iCopy);
  110.     EnableItem(GetMHandle(mEdit), iPaste);
  111.     EnableItem(GetMHandle(mEdit), iClear);
  112.     
  113.     HierFontMenu(    GetMHandle(fontMenuID),
  114.                     rStartOfHeirMenus,
  115.                     (fontFilterProc) nil,
  116.                     noInstancesFontMenu);
  117. }
  118.  
  119.  
  120. /**\
  121. |**| ---------------------------------------------------------------------
  122. |**| DoDraw()
  123. |**| Draw the contents of the window.  The first parameter is the window
  124. |**| to draw, and the second parameter is true if we're updating an existing
  125. |**| image.  If that's the case, we don't want to change anything, but
  126. |**| just draw what's already there.
  127. |**| ---------------------------------------------------------------------
  128. \**/
  129. void DoDraw (WindowPtr wind, Boolean updating)
  130. {
  131.      #pragma unused (updating)
  132. //     GXDrawShape (GetDocShape(wind));
  133.     LayoutEditUpdate( GetDocLEHandle(wind) );
  134. }
  135.  
  136.  
  137. /**\
  138. |**| ---------------------------------------------------------------------
  139. |**| DoCreateNew()
  140. |**| This routine is called when a window needs to be created.
  141. |**| ---------------------------------------------------------------------
  142. \**/
  143. OSErr DoCreateNew (void)
  144. {
  145.     OSErr        err = noErr;
  146.     WindowPtr    wind;
  147.     
  148. // Get and create our window from the resource fork
  149.  
  150.     wind = GetNewWindow(rWindResource, nil, (WindowPtr)-1L);
  151.  
  152. // Attach a default gxViewPort to it, create and iInitialize our
  153. // private data for it, and add a sample image to its page shape.
  154.  
  155.     if ( wind == NULL )
  156.         return (MemError());
  157.  
  158.     GXIgnoreGraphicsNotice(transform_already_set);
  159.     SetDefaultViewPort(GXNewWindowViewPort(wind));            
  160.     GXPopGraphicsNotice();
  161.     
  162.     err = DoWindowInit(wind);
  163.     if ( err != noErr )
  164.         return err;
  165.     
  166.     CreateSampleImage(wind);
  167.     return err;
  168. }
  169.  
  170.  
  171. /**\
  172. |**| ---------------------------------------------------------------------
  173. |**| DoDispose()
  174. |**| This routine is called when a window needs to be disposed of.
  175. |**| ---------------------------------------------------------------------
  176. \**/
  177. void DoDispose (WindowPtr wind)
  178. {
  179.     TH_Doc    doc;
  180.     
  181. // You should always dispose of your GX graphics objects before tossing your window.
  182. // Why?  It's generally good form and this approach guarantees that everything is
  183. // disposed.  If you had not disposed of everything, the call to DisposeWindow should
  184. // dispose of the objects. If you are running the debugging version of QuickDraw GX
  185. // with notices set, you will receive a notice that you had not disposed of everything.
  186. // You can turn notices on in this file by setting gDebugging = TRUE (above).
  187.     
  188.     if ( wind != NULL )
  189.     {
  190.         doc = (TH_Doc)GetWRefCon(wind);        // Remember, this is where we stored our private data.
  191.         GXDisposeShape(GetDocShape(wind));     // Dispose of this doc's shape.
  192.         GXDisposeJob(GetDocJob(wind));        // Dispose of this doc's print job.
  193.         DisposHandle((Handle) doc);            // Dispose of our private data.
  194.         DisposeWindow(wind);                // Dispose of the window.
  195.     }
  196. }
  197.  
  198.  
  199. /**\
  200. |**| ---------------------------------------------------------------------
  201. |**| DoIdle()
  202. |**| This routine is called to do things while idling through the event loop.
  203. |**| ---------------------------------------------------------------------
  204. \**/
  205. void DoIdle (WindowPtr wind)
  206. {
  207.     LayoutEditIdle( GetDocLEHandle(wind) );
  208. }
  209.  
  210.  
  211. /**\
  212. |**| ---------------------------------------------------------------------
  213. |**| DoTeardown()
  214. |**| This routine is called just before we quit to remove anything 
  215. |**| persistent that might have been setup by DoSetup().
  216. |**| ---------------------------------------------------------------------
  217. \**/
  218. void DoTeardown (void)
  219. {
  220.     DisposeRoutineDescriptor(gOurPrintingOverrideUPP);
  221. }
  222.  
  223.  
  224. /**\
  225. |**| ---------------------------------------------------------------------
  226. |**| DoClick()
  227. |**| ---------------------------------------------------------------------
  228. \**/
  229. void DoClick(WindowPtr window, Point p)
  230. {
  231.     gxPoint hitDown;
  232.     gxValidationLevel     currentValidation;
  233.  
  234. //    Unfortunately, GXConvertQDPoint(..) will not survive validation with the QD GX ß2
  235. //    seed. Therefore, we get the validation level set up by the application,  and turn the
  236. //    validation off. We will reset the validation to it's original setting below.
  237. //
  238. //    This problem has already been fixed in the QD GX ß3 build, therefore this work around 
  239. //    will be removed at ß3. Details about the parameters for the GXConvertQDPoint (..) call
  240. //    can be found in the QD GX ß2 Graphics Notes within the "• Open Me First •" folder.
  241.  
  242.     currentValidation = GXGetValidation();
  243.     if (currentValidation) GXSetValidation(gxNoValidation);
  244.     
  245.     /**  Convert the global Quickdraw coordinates to local fixed coordinates.  **/
  246.     GXConvertQDPoint(&p, 0, &hitDown);
  247.  
  248.  
  249. //    Reset the validation to the original setting.
  250.  
  251.     if (currentValidation) GXSetValidation(currentValidation);
  252.  
  253.     LayoutEditClick( GetDocLEHandle(window), hitDown, false);
  254. }
  255.  
  256.  
  257.  
  258.  
  259.  
  260. /**\
  261. |**| ---------------------------------------------------------------------
  262. |**| DoWindowInit()
  263. |**| In this function we create and initialize the the private document
  264. |**| structure for a new window.  This structure contains the print job and
  265. |**| the shape which is drawn in the window.  We store this data in a handle
  266. |**| and hang it off the window's refCon field for easy retrieval.  By doing
  267. |**| this, rather than using globals, we can create many windows containing
  268. |**| unique print jobs and shapes.
  269. |**| ---------------------------------------------------------------------
  270. \**/
  271. OSErr DoWindowInit (WindowPtr wind)
  272. {
  273.     OSErr    err = noErr;
  274.     gxJob    docJob;
  275.     gxShape    docPage;
  276.     gxShape    docErase;
  277.     TH_Doc    windDoc;
  278.  
  279.  
  280. // Create the page shape. We set the unique items attribute to make sure that each item
  281. // added to the picture has a unique reference. If this attribute was not set, we would
  282. // not see all copies of anything we add to the shape multiple times -- we'd just see
  283. // the last version added.        
  284.  
  285.     docPage = GXNewShape(gxPictureType);
  286.     GXSetShapeAttributes(docPage, (GXGetShapeAttributes(docPage) | gxUniqueItemsShape));
  287.     
  288.     
  289. // Create the erase shape. We set the unique items attribute to make sure that each item
  290. // added to the picture has a unique reference. If this attribute was not set, we would
  291. // not see all copies of anything we add to the shape multiple times -- we'd just see
  292. // the last version added.        
  293.  
  294.     docErase = GXNewShape(gxPictureType);
  295.     GXSetShapeAttributes(docErase, (GXGetShapeAttributes(docErase) | gxUniqueItemsShape));
  296.     
  297.     
  298. // Create a print job for this document.  This will be the same as the system default until
  299. // the user goes through the dialogs for Page Setup or Print…
  300.  
  301.     err = GXNewJob(&docJob);
  302.     
  303.     
  304. // If there are no errors, create a handle the size of our document structure and store
  305. // the print job and page shape in it.  Store the handle in the window's refCon field so
  306. // that we can get at it.  (Note that the utility routines "GetDocJob" and "GetDocShape"
  307. // can be used to do this easily.
  308.  
  309.     if ( err == noErr )
  310.     {
  311.         windDoc = (TH_Doc) NewHandleClear(sizeof(T_Doc));
  312.  
  313.         if ( windDoc == NULL )
  314.             err = MemError();
  315.         else
  316.         {
  317.             (*windDoc)->docJob = docJob;
  318.             (*windDoc)->docPage = docPage;
  319.             (*windDoc)->docLEHandle = nil;
  320.             SetWRefCon(wind, (long) windDoc);
  321.         }
  322.  
  323. // Now install our application override for PrintingEvent so that we can
  324. // support the new movable-modal printing dialog boxes.
  325.  
  326.         GXInstallApplicationOverride(docJob, gxPrintingEventMsg, gOurPrintingOverrideUPP);
  327.  
  328.     }
  329.  
  330.     return err;
  331. }
  332.  
  333.  
  334. /**\
  335. |**| ---------------------------------------------------------------------
  336. |**| CreateSampleImage()
  337. |**| This function creates primitive shapes and adds them to the window's page shape.
  338. |**| ---------------------------------------------------------------------
  339. \**/
  340. void CreateSampleImage (WindowPtr wind)
  341. {
  342.     Rect    ourWindowRect = wind->portRect; // the rectangle for this window
  343.                                             // in QuickDraw coordinates
  344.     gxShape layout;                        // the layout shape we build
  345.     gxShape thePage;                    // this window's document shape
  346.     gxRunControls runControls;            // run controls for the layout shape
  347.     gxLayoutOptions layoutOptions;        // options for the layout shape
  348.     gxStyle timesStyle;                    // a style record for a Times-based style
  349.     gxStyle hoeflerStyle;                // ditto for Helvetica
  350.     gxStyle baghdadStyle;                 // ditto for Baghdad
  351.     gxStyle textStyles[4];                // an array of text style for our text runs
  352.     
  353. // These are the five text runs for this layout shape, in pieces because they're
  354. // in different languages
  355.     
  356.     char *text1 = "The wicked ";
  357.     char *text2 = "fast ";
  358.     
  359. // The following is "Macintosh" in Arabic: 
  360. // meem, alif, kaf,  noon, tah,  wau,  shin
  361. // (This assumes the standard Arabic character set for Macintosh, by the way)
  362.     
  363.     static char text3[] = {0xE5, 0xC7, 0xE3, 0xE6, 0xCA, 0xE8, 0xD4, 0};
  364.     
  365.     char *text4 = " lives!";
  366.  
  367.  
  368.     char *textRuns[4];                    // an array of pointers to text runs
  369.  
  370.     short textLengths[4];                // an array of the lengths of each run
  371.     short totalLength;                    // the total length of the layout's text
  372. //    static short levelRunLengths[3];    // an array of the lengths of each level
  373. //    static short levels[3] = {0, 1, 0};    // the level numbers for each level
  374.     short levels = 0;
  375.     
  376.     gxPoint posn;                        // the position of the layout shape
  377.  
  378.  
  379. // First, initialize the textRuns array to point to the five text runs
  380.     
  381.     textRuns[0] = text1;
  382.     textRuns[1] = text2;
  383.     textRuns[2] = text3;
  384.     textRuns[3] = text4;
  385.     
  386.     
  387. // Initialize the text lengths.
  388.  
  389.     textLengths[0] = MyStrLength(text1);
  390.     textLengths[1] = MyStrLength(text2);
  391.     textLengths[2] = MyStrLength(text3);
  392.     textLengths[3] = MyStrLength(text4);
  393.     
  394. // Our layout has three levels in it -- level 0 for the English runs at each end,
  395. // and level 1 for the Arabic text in the middle.  We need the byte-count for each
  396. // level's text run in the levelRunLengths array.
  397.  
  398. //    levelRunLengths[0] = textLengths[0];
  399. //    levelRunLengths[1] = textLengths[1] + textLengths[2] + textLengths[3];
  400. //    levelRunLengths[2] = textLengths[4];
  401.  
  402.     
  403. // totalLength is the length of all the text.
  404.  
  405.     totalLength = textLengths[0] + textLengths[1] + textLengths[2] + textLengths[3];
  406.     
  407.  
  408. // make default gxLayoutOptions and gxRunControls structures
  409.  
  410.     InitializeLayoutOptions (&layoutOptions);
  411.     InitializeRunControls (&runControls);
  412.     
  413. // Position the layout half way down the left edge of the window. Set 
  414. // the layout's width to the window's width and set the flushness to 1/2, this
  415. // will cause the layout to center in the window.  Note that ourWindowRect is
  416. // not in fixed coordinates, so we have to make it fixed to use it.
  417.  
  418.     layoutOptions.width = ff(ourWindowRect.right - ourWindowRect.left);
  419.     layoutOptions.flush = fract1/2;
  420.  
  421.     posn.x = 0;
  422.     posn.y = ff((ourWindowRect.bottom - ourWindowRect.top) / 2);
  423.     
  424.  
  425. // Create the styles we'll use.  The helveticaStyle is 30-point Helvetica.
  426. // NewLayoutStyle is a library routine found in layout library.c.  But first,
  427. // this important message:
  428.  
  429. // When I was converting this sample to actually print, I found this strange
  430. // problem that the highlight shape, while appearing correctly on the screen,
  431. // was always too far to the right when printed -- sometimes overlapping parts
  432. // of glyphs that shouldn't be highlighted.  An investigation was launched.
  433. //
  434. // It turns out that highlight shapes are pretty much always 72 DPI, because
  435. // they're polygons calculated from the metrics of the layout shape when the
  436. // highlight shape is created.  If you then scale the layout shape by
  437. // transforming it to 300 DPI or so (like a printer driver would do), the
  438. // highlight shape has the same geometry while hinting of the glyphs may have
  439. // changed the way the layout shape looks.  They've moved a little bit, perhaps,
  440. // and therefore the highlight shape isn't in the right place anymore.
  441. //
  442. // If this is for your on-screen work, you can recreate the highlight shape in
  443. // a zoomed viewPort, but you don't get to make the printer driver do that for
  444. // you.  So, instead, for each style run we use, we add the gxNoMetricsGridText
  445. // attribute.  This prevents QuickDraw GX from using hinting, so the glyphs always
  446. // scale the same way the highlight shape does, and all is well.
  447. //
  448. // (At first, I tried to fix this by adding gxNoMetricsGridShape to the layout
  449. // _shape's_ attributes, but that's not the right idea.  The attributes in the
  450. // shape's style affect any part of the layout that doesn't have a style of its
  451. // own, including any parts of the text for which the entry in the style array
  452. // is nil.  Since we're actually applying styles over the layout here, the
  453. // gxNoMetricsGridText must be set in those styles, not in the shape's style.)
  454. //
  455. // This does mean that your glyphs won't get hinting at low resolutions and
  456. // small point sizes where it might be desirable -- but it's really only a problem
  457. // if you're trying to print a highlight shape, which doesn't happen very often.
  458. // In fact, I can't really think of a legitimate reason to want to do it, except
  459. // maybe in sample code.
  460.     
  461.     hoeflerStyle = NewLayoutStyle(
  462.         (char *) "\pHoefler Text",            // the gxFontName for the style
  463.         ff(30),                                // the text size in fixed point
  464.         gxNoMetricsGridText,                // gxTextAttributes
  465.         &runControls,                        // run controls (our default ones)
  466.         nil,                                // run features (none for this style)
  467.         0,                                    // count of run features
  468.         nil);                                // style run overrides (none right now)
  469.  
  470. // The second style is baghdadStyle -- Baghdad Plain (Arabic), 30 points.
  471.  
  472.     baghdadStyle = NewLayoutStyle(
  473.         (char *) "\pBaghdad Plain",            // gxFontName
  474.         ff(30),                                // text size (fixed point)
  475.         gxNoMetricsGridText,                // gxTextAttributes
  476.         &runControls,                        // run controls (our default ones)
  477.         nil,                                 // run features (none)
  478.         0,                                     // count of run features (none)
  479.         nil);                                // style run overrides (none)
  480.     
  481. // The final style is 30-point Times Roman.
  482.  
  483.     timesStyle = NewLayoutStyle(
  484.         (char *) "\pTimes Roman",             // gxFontName
  485.         ff(30),                             // text size (fixed point)
  486.         gxNoMetricsGridText,                // gxTextAttributes
  487.         &runControls,                         // run controls (our default ones)
  488.         nil,                                 // run features (none)
  489.         0,                                     // count of run features (none)
  490.         nil);                                // style run overrides (none)
  491.     
  492.  
  493. // Initialize the textStyles array so that each of the five runs has the right style
  494.  
  495.     textStyles[0] = hoeflerStyle;
  496.     textStyles[1] = timesStyle;
  497.     textStyles[2] = baghdadStyle;
  498.     textStyles[3] = hoeflerStyle;
  499.     
  500.  
  501. // Setup complete!  Build the layout.
  502.  
  503.     layout = GXNewLayout(
  504.         4,                                // count of text runs
  505.         textLengths,                    // array of lengths of each run
  506.         (void *) textRuns,                // array of pointers to the text
  507.         4,                                // count of style runs
  508.         textLengths,                    // array of the byte lengths of each run
  509.         textStyles,                        // array of the styles
  510.         1,                                // number of levels in the layout
  511.         &totalLength,                    // array of the lengths of each level
  512.         &levels,                        // array of the levels
  513.         &layoutOptions,                    // options (default)
  514.         &posn);                            // position of the layout shape
  515.  
  516.     GXSetShapeStyle(layout, hoeflerStyle);
  517.     
  518.     
  519.     
  520. // Retrieve the page shape so we can add to it.
  521.  
  522.     thePage = GetDocShape(wind);
  523.     
  524. // Add the layout to the window's picture shape.  AddToShape is in shape library.c.
  525.  
  526.     AddToShape(thePage, layout);
  527.  
  528.  
  529. // build LayoutEditHandle and attatch to this windows document
  530. //    layoutHandle = LayoutEditHandleFromLayout(layout);
  531.     if ( wind != NULL )
  532.     {
  533.         TH_Doc    doc = (TH_Doc) GetWRefCon(wind);
  534.         (*doc)->docLEHandle = LayoutEditHandleFromLayout(layout);
  535.     }
  536.  
  537.  
  538. // Dispose of what we allocated
  539.  
  540. //    GXDisposeShape(layout);
  541.     GXDisposeStyle(hoeflerStyle);
  542.     GXDisposeStyle(baghdadStyle);
  543.     GXDisposeStyle(timesStyle);
  544.     
  545.  
  546. // Invalidate the window's portRect so that everything gets updated.
  547.     
  548.     SetPort(wind);
  549.     InvalRect(&ourWindowRect);
  550. }
  551.  
  552.